/*
 * Copyright (C) 2005 - 2013 MaNGOS <http://www.getmangos.com/>
 *
 * Copyright (C) 2008 - 2013 Trinity <http://www.trinitycore.org/>
 *
 * Copyright (C) 2010 - 2013 ProjectSkyfire <http://www.projectskyfire.org/>
 *
 * Copyright (C) 2011 - 2013 ArkCORE <http://www.arkania.net/>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#ifndef ARKCORE_MAIL_H
#define ARKCORE_MAIL_H

#include "Common.h"
#include <map>

struct AuctionEntry;
class Item;
class Object;
class Player;

#define MAIL_BODY_ITEM_TEMPLATE 8383                        // - plain letter, A Dusty Unsent Letter: 889
#define MAX_MAIL_ITEMS 12

enum MailMessageType
{
    MAIL_NORMAL = 0, MAIL_AUCTION = 2, MAIL_CREATURE = 3,          // client send CMSG_CREATURE_QUERY on this mailmessagetype
    MAIL_GAMEOBJECT = 4,          // client send CMSG_GAMEOBJECT_QUERY on this mailmessagetype
    MAIL_ITEM = 5,
// client send CMSG_ITEM_QUERY on this mailmessagetype
};

enum MailCheckMask
{
    MAIL_CHECK_MASK_NONE = 0x00, MAIL_CHECK_MASK_READ = 0x01, MAIL_CHECK_MASK_RETURNED = 0x02,          /// This mail was returned. Do not allow returning mail back again.
    MAIL_CHECK_MASK_COPIED = 0x04,          /// This mail was copied. Do not allow making a copy of items in mail.
    MAIL_CHECK_MASK_COD_PAYMENT = 0x08, MAIL_CHECK_MASK_HAS_BODY = 0x10,
/// This mail has body text.
};

// gathered from Stationery.dbc
enum MailStationery
{
    MAIL_STATIONERY_TEST = 1, MAIL_STATIONERY_DEFAULT = 41, MAIL_STATIONERY_GM = 61, MAIL_STATIONERY_AUCTION = 62, MAIL_STATIONERY_VAL = 64, MAIL_STATIONERY_CHR = 65,
};

enum MailState
{
    MAIL_STATE_UNCHANGED = 1, MAIL_STATE_CHANGED = 2, MAIL_STATE_DELETED = 3
};

enum MailAuctionAnswers
{
    AUCTION_OUTBIDDED = 0, AUCTION_WON = 1, AUCTION_SUCCESSFUL = 2, AUCTION_EXPIRED = 3, AUCTION_CANCELLED_TO_BIDDER = 4, AUCTION_CANCELED = 5, AUCTION_SALE_PENDING = 6
};

enum MailShowFlags
{
    MAIL_SHOW_UNK0 = 0x0001, MAIL_SHOW_DELETE = 0x0002,          // forced show delete button instead return button
    MAIL_SHOW_AUCTION = 0x0004,          // from old comment
    MAIL_SHOW_UNK2 = 0x0008,          // unknown, COD will be shown even without that flag
    MAIL_SHOW_RETURN = 0x0010,
};

class MailSender
{
public:
    // Constructors
    MailSender (MailMessageType messageType, uint32 sender_guidlow_or_entry, MailStationery stationery = MAIL_STATIONERY_DEFAULT) :
            m_messageType(messageType), m_senderId(sender_guidlow_or_entry), m_stationery(stationery)
    {
    }
    MailSender (Object* sender, MailStationery stationery = MAIL_STATIONERY_DEFAULT);
    MailSender (AuctionEntry* sender);
    MailSender (Player* sender);
public:
    // Accessors
    MailMessageType GetMailMessageType () const
    {
        return m_messageType;
    }
    uint32 GetSenderId () const
    {
        return m_senderId;
    }
    MailStationery GetStationery () const
    {
        return m_stationery;
    }
private:
    MailMessageType m_messageType;
    uint32 m_senderId;          // player low guid or other object entry
    MailStationery m_stationery;
};

class MailReceiver
{
public:
    // Constructors
    explicit MailReceiver (uint32 receiver_lowguid) :
            m_receiver(NULL), m_receiver_lowguid(receiver_lowguid)
    {
    }
    MailReceiver (Player* receiver);
    MailReceiver (Player* receiver, uint64 receiver_lowguid);
public:
    // Accessors
    Player* GetPlayer () const
    {
        return m_receiver;
    }
    uint32 GetPlayerGUIDLow () const
    {
        return m_receiver_lowguid;
    }
private:
    Player* m_receiver;
    uint32 m_receiver_lowguid;
};

class MailDraft
{
    typedef std::map<uint32, Item*> MailItemMap;

public:
    // Constructors
    explicit MailDraft (uint16 mailTemplateId, bool need_items = true) :
            m_mailTemplateId(mailTemplateId), m_mailTemplateItemsNeed(need_items), m_money(0), m_COD(0)
    {
    }
    MailDraft (std::string subject, std::string body) :
            m_mailTemplateId(0), m_mailTemplateItemsNeed(false), m_subject(subject), m_body(body), m_money(0), m_COD(0)
    {
    }
public:
    // Accessors
    uint16 GetMailTemplateId () const
    {
        return m_mailTemplateId;
    }
    std::string const& GetSubject () const
    {
        return m_subject;
    }
    uint64 GetMoney () const
    {
        return m_money;
    }
    uint64 GetCOD () const
    {
        return m_COD;
    }
    std::string const& GetBody () const
    {
        return m_body;
    }

public:
    // modifiers
    MailDraft& AddItem (Item* item);
    MailDraft& AddMoney (uint64 money)
    {
        m_money = money;
        return *this;
    }
    MailDraft& AddCOD (uint64 COD)
    {
        m_COD = COD;
        return *this;
    }

public:
    // finishers
    void SendReturnToSender (uint32 sender_acc, uint32 sender_guid, uint32 receiver_guid, SQLTransaction& trans);
    void SendMailTo (SQLTransaction& trans, MailReceiver const& receiver, MailSender const& sender, MailCheckMask checked = MAIL_CHECK_MASK_NONE, uint32 deliver_delay = 0);

private:
    void deleteIncludedItems (SQLTransaction& trans, bool inDB = false);
    void prepareItems (Player* receiver, SQLTransaction& trans);          // called from SendMailTo for generate mailTemplateBase items

    uint16 m_mailTemplateId;
    bool m_mailTemplateItemsNeed;
    std::string m_subject;
    std::string m_body;

    MailItemMap m_items;          // Keep the items in a map to avoid duplicate guids (which can happen), store only low part of guid

    uint64 m_money;
    uint64 m_COD;
};

struct MailItemInfo
{
    uint32 item_guid;
    uint32 item_template;
};
typedef std::vector<MailItemInfo> MailItemInfoVec;

struct Mail
{
    uint32 messageID;
    uint8 messageType;
    uint8 stationery;
    uint16 mailTemplateId;
    uint32 sender;
    uint32 receiver;
    std::string subject;
    std::string body;
    std::vector<MailItemInfo> items;
    std::vector<uint32> removedItems;
    time_t expire_time;
    time_t deliver_time;
    uint64 money;
    uint64 COD;
    uint32 checked;
    MailState state;

    void AddItem (uint32 itemGuidLow, uint32 item_template)
    {
        MailItemInfo mii;
        mii.item_guid = itemGuidLow;
        mii.item_template = item_template;
        items.push_back(mii);
    }

    bool RemoveItem (uint32 item_guid)
    {
        for (MailItemInfoVec::iterator itr = items.begin(); itr != items.end(); ++itr)
        {
            if (itr->item_guid == item_guid)
            {
                items.erase(itr);
                return true;
            }
        }
        return false;
    }

    bool HasItems () const
    {
        return !items.empty();
    }
};

#endif
